﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Ankha.ContentPipeline;
using Ankha.Core;
using Ivory.Libs;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Ankha
{
    public class ScreenManager
    {
        private static Log _DebugLogInstance;
        public static Log DebugLogInstance
        {
            get
            {
                if (_DebugLogInstance == null)
                    _DebugLogInstance = new Log("Debug.debug", "Debug");

                return _DebugLogInstance;
            }
        }

        public static Game GameBase { get; private set; }

        //Fields
        public ScreenDisplayMode DisplayMode { get; set; }        
        public Pipeline ContentPipeline { get; private set; }

        public Rectangle WindowRect
        {
            get { return new Rectangle(0, 0, _GDM.PreferredBackBufferWidth, _GDM.PreferredBackBufferHeight); }
        }
        public Vector2 WindowRez
        {
            get { return new Vector2(_GDM.PreferredBackBufferWidth, _GDM.PreferredBackBufferHeight); }
        }

        private string _CurrentGameScreen = "null";
        public string CurrentGameScreen
        {
            get { return _CurrentGameScreen; }
            set
            {
                //TODO:
            }
        }

        private MenuScreen _MenuScreen;
        private Queue<SplashScreen> _SplashScreens;        
        private Dictionary<string, GameScreen> _GameScreens;
        
        private GraphicsDeviceManager _GDM; 
        private Config _Config;

        private InputControl _InputController;
        private FPSCounter _FPSCounter;
        private FrameTimes _RenderTime, _LogicTime;

        //cTor
        public ScreenManager(Game game, string configFile = "data/config.cfg")
        {
            _MenuScreen = null;
            _SplashScreens = new Queue<SplashScreen>();
            _GameScreens = new Dictionary<string, GameScreen>();

            GameBase = game;
            GameBase.Content.RootDirectory = "Content";
            GameBase.Exiting += OnGameExit;

            _Config = new Config(GameBase.Content.RootDirectory + "/" + configFile);
            Init();
        }

        //Methods
        private void OnGameExit(object sender, EventArgs e)
        {
            _Config.SaveConfigFile();
        }

        public void AddSplashScreen(SplashScreen screen)
        {
            DisplayMode = ScreenDisplayMode.Splash;
            _SplashScreens.Enqueue(screen);
        }
        public void SetMenuScreen(MenuScreen screen)
        {
            this._MenuScreen = screen;
        }
        public void AddGameScreen(string key, GameScreen screen)
        {
            _GameScreens.Add(key, screen);
        }
        
        public void Init()
        {
            DisplayMode = ScreenDisplayMode.Menu;

            ContentPipeline = new Pipeline();
            _InputController = new InputControl(GameBase);
            _FPSCounter = new FPSCounter();            
            _RenderTime = new FrameTimes();
            _LogicTime = new FrameTimes();

            _GDM = new GraphicsDeviceManager(GameBase);
            _GDM.PreferredBackBufferWidth = _Config.GetValueByFlag<int>("width");
            _GDM.PreferredBackBufferHeight = _Config.GetValueByFlag<int>("height");
            _GDM.IsFullScreen = _Config.GetValueByFlag<bool>("fullscreen");
            _GDM.GraphicsProfile = (_Config.GetValueByFlag<bool>("hidef") ? GraphicsProfile.HiDef : GraphicsProfile.Reach);
            _GDM.PreferMultiSampling = _Config.GetValueByFlag<bool>("multisampling");
            _GDM.SynchronizeWithVerticalRetrace = _Config.GetValueByFlag<bool>("vsync");
            GameBase.IsMouseVisible = _Config.GetValueByFlag<bool>("mousevisible");
            _GDM.ApplyChanges();
            DebugLogInstance.WriteString("Settings loaded & applied from config");
        }
        public void Load()
        {
            ContentPipeline.LoadPipeline();
        }

        public void Render(GameTime time)
        {
            using(SpriteBatch renderBatch = new SpriteBatch(GameBase.GraphicsDevice))
            {
                if (DisplayMode == ScreenDisplayMode.Splash)
                {
                    throw new NotImplementedException("Not Yet Supported!");
                }
                else if (DisplayMode == ScreenDisplayMode.Menu)
                {
                    _MenuScreen.RenderScreen(renderBatch, time);
                }
                else if (DisplayMode == ScreenDisplayMode.Game)
                {
                    _GameScreens[CurrentGameScreen].RenderScreen(renderBatch, time);
                }

                //Render FPS and frametimes
                renderBatch.Begin();
                string infoText = string.Format("FPS: {0} \nRender Time: {1} \nLogic Time: {2}", _FPSCounter.FPS, _RenderTime, _LogicTime);
                Vector2 fpsPos = new Vector2(0, GameBase.GraphicsDevice.Viewport.Height - FontLibrary.Instance.GetFont("default").MeasureString(infoText).Y);

                renderBatch.DrawString(FontLibrary.Instance.GetFont("default"), infoText, fpsPos, Color.Black);
                renderBatch.DrawString(FontLibrary.Instance.GetFont("default"), infoText, fpsPos + Vector2.One, Color.White);

                renderBatch.End();
            }
        }
        public void Update(GameTime time)
        {
            _FPSCounter.Update(time);
            _InputController.Update(time);
            _RenderTime.StartFrame();
            _LogicTime.StartFrame();

            if (DisplayMode == ScreenDisplayMode.Splash)
            {
                throw new NotImplementedException("Not Yet Supported!");
            }
            else if (DisplayMode == ScreenDisplayMode.Menu)
            {
                _MenuScreen.UpdateScreen(_InputController, time);
            }
            else if (DisplayMode == ScreenDisplayMode.Game)
            {
                _GameScreens[CurrentGameScreen].UpdateScreen(_InputController, time);
            }

            _RenderTime.EndFrame(time);
            _LogicTime.EndFrame(time);
        }
    }
}
